render hooks pattern
Custom HooksからComponentを提供する
#WIP
https://zenn.dev/fizumi/articles/083db23e25106e
Custom Hook から Component を返却する render hooks パターンの場合、返却された Component がアンマウントされてしまうことによりバグが発生する恐れがあるので注意が必要です。
Custom Hook から Component を返さずに React element を返す実装にすれば、 アンマウントを回避できます。
https://twitter.com/cubbit2/status/1487052070691606531/retweets/with_comments
【LINE証券 FrontEnd】コンポーネントをカスタムフックで提供してみた - LINE ENGINEERING
https://twitter.com/uhyo_/status/1521011098920665088
componentは含めないのか
useEventがあるとましになりそうな気もする
https://blog.bitsrc.io/new-react-design-pattern-return-component-from-hooks-79215c3eac00
/miyamonz/render hooks パターン
https://zenn.dev/mssknd/articles/1046a44b9d9502
ロジックとcomponentが明らかに凝集している、という場合に有用
react-hooks-use-modal
https://github.com/microcmsio/react-hooks-use-modal
ModalというComponentを返している
code:ts
const App = () => {
const Modal, open, close, isOpen = useModal('root', {
preventScroll: true,
closeOnOverlayClick: false
});
return (
<div>
<p>Modal is Open? {isOpen ? 'Yes' : 'No'}</p>
<button onClick={open}>OPEN</button>
<Modal>
<div>
<h1>Title</h1>
<p>This is a customizable modal.</p>
<button onClick={close}>CLOSE</button>
</div>
</Modal>
</div>
);
};
https://github.com/microcmsio/react-hooks-use-modal/blob/5c7e3f90dd01c1135dec87915e40669e6e8f7251/src/index.tsx#L93-L102
実装箇所
useCallback使ってる
https://blog.microcms.io/how-to-react-hooks-use-modal/
うまく動かない例
code:ts
const useForm = () => {
const value, setValue = useState('');
const Field: React.FC = useCallback(
() => <input value={value} onChange={e => setValue(e.target.value)} />,
value,
);
return {
Field,
};
};
値が入力されるたびにFieldが新しく作られるので、1文字入力するたびにフォーカスが外れてしまう
https://gyazo.com/7831821d2cf02d14c5a15793d777bac5
どうしてもこういうAPIを提供したいならuseRef使ってハックっぽくするとか
code:ts
const useForm = () => {
const valueRef = useRef('');
const Field: React.FC = () => {
const inputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
if (inputRef.current) {
inputRef.current.value = valueRef.current;
}
}, []);
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
valueRef.current = e.target.value;
};
return <input ref={inputRef} onChange={onChange} />;
};
return {
Field,
};
};
ちなみにこうかくとめちゃくちゃバグる
code:ts
const useForm = () => {
const value, setValue = useState('');
const ref = useRef(value);
useEffect(() => {
ref.current = value;
}, value);
const Field: React.FC = useCallback(
() => (
<input value={ref.current} onChange={(e) => setValue(e.target.value)} />
),
[]
);
return {
Field,
};
};